package topcbl.room;

//pass code.google.com dD2gC2zS2Vu9
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Vector;

import topcbl.ai.DominoAI;
import topcbl.game.ListGame;
import topcbl.gamewithme.R;
import topcbl.util.Utils;
import android.app.Activity;
import android.app.Dialog;
import android.app.Fragment;
import android.app.FragmentManager;
import android.content.Context;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.StrictMode;
import android.support.v13.app.FragmentStatePagerAdapter;
import android.support.v4.view.ViewPager;
import android.util.Log;
import android.view.GestureDetector;
import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import android.widget.SlidingDrawer;
import android.widget.TextView;

enum Team {
	TRAI, PHAI
}

public class MainActivity extends Activity implements View.OnClickListener {

	public static ServerThread mServer = null;
	public static ClientThread mClient = null;
	Handler handler = new Handler();
 
	// tạo UI
	Button createRoom, joinRoom, startGame, cancelRoom, ready, quitRoom;
	EditText namePlayer;
	ViewPager viewPager;
	ListGameAdapter listGameAdapter;
	ListGame mListGame = new ListGame();
	ViewGroup teamTraiUI, teamPhaiUI;
	Vector<MyGestureDetector> handleEvents4Room = new Vector<MyGestureDetector>();

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		// create UI Button
		createRoom = (Button) findViewById(R.id.button_create);
		joinRoom = (Button) findViewById(R.id.button_join);
		startGame = (Button) findViewById(R.id.button_startgame);
		cancelRoom = (Button) findViewById(R.id.button_cancelroom);
		quitRoom = (Button) findViewById(R.id.button_quitroom);
		namePlayer = (EditText) findViewById(R.id.editText1);
		createRoom.setOnClickListener(this);
		joinRoom.setOnClickListener(this);
		startGame.setOnClickListener(this);
		cancelRoom.setOnClickListener(this);
		quitRoom.setOnClickListener(this);
		namePlayer.setText("Dummy");

		// create team 1 and team 2
		teamTraiUI = (ViewGroup) findViewById(R.id.phe1);
		teamPhaiUI = (ViewGroup) findViewById(R.id.phe2);

		// Instantiate slide image to choose game
		viewPager = (ViewPager) findViewById(R.id.pager);
		listGameAdapter = new ListGameAdapter(getFragmentManager());
		viewPager.setAdapter(listGameAdapter);
		viewPager
				.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
					@Override
					public void onPageSelected(int position) {
						mListGame.setPosition(position);
					}
				});

		// Permit use network in main thread
		StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder()
				.permitAll().build();
		StrictMode.setThreadPolicy(policy);

		// Long click to add AI
		findViewById(R.id.them_ai).setOnLongClickListener(
				new View.OnLongClickListener() {

					@Override
					public boolean onLongClick(View v) {
						DominoAI bot = new DominoAI("Bot easy");
						mServer.mRoom.addPlayer(bot);
						addUIPlayer(bot);
						// send new player to all player who connected before
						mServer.mRoom.send2AllPlayer("ADD_" + bot.getName()
								+ ":" + bot.getTeam());
						return false;
					}
				});
	}

	@Override
	public void onClick(View v) {
		try {
			if (v == createRoom) {
				mServer = new ServerThread();
				mServer.execute();
				findViewById(R.id.group_btn_first).setVisibility(View.GONE);
				findViewById(R.id.group_btn_server).setVisibility(View.VISIBLE);
			} else if (v == joinRoom) {
				new EnterIpDialog(MainActivity.this).show();
			} else if (v == startGame) {
				if (mServer.mRoom.canPlay()) {
					mServer.mRoom.send2AllPlayer("START_0");
					mListGame.createGame(MainActivity.this);
					mServer.isHeartBeat = false;
					mServer.cancel(true);
				}
			} else if (v == cancelRoom) {
				mServer.isHeartBeat = false; // stop heartbeat
				mServer.mRoom.send2AllPlayer("CANCEL_0");
				mServer.mRoom.closeAllSocket();
				mServer.mServerSocket.close();
				mServer.cancel(true);
				teamPhaiUI.removeAllViews();
				teamTraiUI.removeAllViews();
				findViewById(R.id.group_btn_first).setVisibility(View.VISIBLE);
				findViewById(R.id.group_btn_server).setVisibility(View.GONE);
				findViewById(R.id.text_room).setVisibility(View.VISIBLE);
				namePlayer.setText("");
			} else if (v == quitRoom) {
				mClient.mSocket.close();
				teamPhaiUI.removeAllViews();
				teamTraiUI.removeAllViews();
				mClient.cancel(true);
				findViewById(R.id.group_btn_first).setVisibility(View.VISIBLE);
				findViewById(R.id.group_btn_client).setVisibility(View.GONE);
				findViewById(R.id.text_room).setVisibility(View.VISIBLE);
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * Class support User create Server and manage amount of Clients connect to
	 * 
	 * @author baolong
	 * 
	 */
	public class ServerThread extends AsyncTask<Void, Player, String> {
		public static final int PORT = 9669;
		// public static final String SERVER_IP = "192.168.1.11";
		public static final int PERIOD_HEARTBEAT = 2000;
		ServerSocket mServerSocket;
		Room mRoom;

		@Override
		protected void onPreExecute() {
			mRoom = new Room(4);
			Player serverPlayer = new Player("Server Player^.^");
			mRoom.addPlayer(serverPlayer);
			findViewById(R.id.text_room).setVisibility(View.GONE);
			addUIPlayer(serverPlayer);
			startHeartBeat2CheckClientConnection();
			super.onPreExecute();
		}

		@Override
		protected String doInBackground(Void... params) {
			try {
				mServerSocket = new ServerSocket(PORT);
				publishProgress(null);
				while (!isCancelled()) {
					if (!mRoom.isFull()) {
						Player newPlayer = new Player(mServerSocket.accept());
						newPlayer.createName();
						// send all player who connected before to new player
						for (int i = 0; i < mRoom.teamTrai.size(); i++) {
							newPlayer.sendMessage("ADD_"
									+ mRoom.teamTrai.get(i).getName() + ":"
									+ mRoom.teamTrai.get(i).getTeam());
						}
						for (int i = 0; i < mRoom.teamPhai.size(); i++) {
							newPlayer.sendMessage("ADD_"
									+ mRoom.teamPhai.get(i).getName() + ":"
									+ mRoom.teamPhai.get(i).getTeam());
						}
						mRoom.addPlayer(newPlayer);
						publishProgress(newPlayer);
						// send new player to all player who connected before
						mRoom.send2AllPlayer("ADD_" + newPlayer.getName() + ":"
								+ newPlayer.getTeam());
					} else {
						// send message back to client that room is full
					}

				}
			} catch (Exception e) {
				e.printStackTrace();
			}
			return "Tạo server và kết nối thành công";
		}

		@Override
		protected void onProgressUpdate(Player... values) {
			if (values == null) {
				namePlayer.setText(Utils.getIPAddress(true));
			} else {
				addUIPlayer(values[0]);
			}
			super.onProgressUpdate(values);
		}

		public Room getRoom() {
			return mRoom;
		}

		public ServerSocket getServerSocket() {
			return mServerSocket;
		}

		/*
		 * Method checking client disconnect
		 */
		int check;
		boolean isHeartBeat = true;

		private void startHeartBeat2CheckClientConnection() {
			Thread heartBeat = new Thread(new Runnable() {

				@Override
				public void run() {
					while (isHeartBeat) {
						for (int i = 0; i < handleEvents4Room.size(); i++) {
							try {
								check = i;
								Player checkingPlayer = handleEvents4Room.get(
										check).getListener().player;
								checkingPlayer.sendMessage("CHECK_0");
								String respond = checkingPlayer
										.receiveMessage();
								if (respond == null) { // player lose connect
									handler.post(new Runnable() {
										@Override
										public void run() {
											handleDisPlayer();
										}
									});
								} else {
									// player still connect
								}
							} catch (Exception e) {
								e.printStackTrace();
							}
						}
						try {
							Thread.currentThread().sleep(
									ServerThread.PERIOD_HEARTBEAT);
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
					}
				}
			});
			heartBeat.start();
		}

		/*
		 * Method handle client disconnect event
		 */
		private void handleDisPlayer() {
			GestureListener disPlayer = handleEvents4Room.get(check)
					.getListener();
			disPlayer.player.closeConnect();
			mServer.mRoom.removePlayer(disPlayer.player);
			if (disPlayer.player.getTeam() == Team.TRAI) {
				teamTraiUI.removeView(disPlayer.holderView);
				mServer.mRoom.send2AllPlayer("REMOVE_"
						+ disPlayer.player.getName() + ":TRAI");
			} else {
				teamPhaiUI.removeView(disPlayer.holderView);
				mServer.mRoom.send2AllPlayer("REMOVE_"
						+ disPlayer.player.getName() + ":PHAI");
			}
			handleEvents4Room.remove(check);
		}
	}

	/**
	 * class support for User when they join room as Client
	 * 
	 * @author baolong
	 * 
	 */
	public class ClientThread extends AsyncTask<Void, String, String> {
		Socket mSocket;
		BufferedReader input;
		PrintWriter output;
		String ip;

		public ClientThread(String IpAddress) {
			ip = IpAddress;
		}

		@Override
		protected void onPreExecute() {
			try {
				InetAddress serverAddr = InetAddress.getByName(ip);
				Socket socket = new Socket(serverAddr, ServerThread.PORT);
				mSocket = socket;
				input = new BufferedReader(new InputStreamReader(
						mSocket.getInputStream()));
				output = new PrintWriter(new BufferedWriter(
						new OutputStreamWriter(mSocket.getOutputStream())),
						true);
				// send player name immediately
				output.println(namePlayer.getText().toString());
			} catch (Exception e) {
				e.printStackTrace();
			}
			super.onPreExecute();
		}

		@Override
		protected String doInBackground(Void... params) {
			try {
				while (!isCancelled()) {
					String data = input.readLine();
					if (data != null)
						publishProgress(data);
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
			return "";
		}

		@Override
		protected void onProgressUpdate(String... values) {
			String[] fromServer = values[0].split("_");
			String control = fromServer[0];
			String data = fromServer[1];
			switch (control) {
			case "ADD":
				findViewById(R.id.text_room).setVisibility(View.GONE);
				addUIPlayer(data);
				break;
			case "CHANGE":
				removeUIPlayer(data);
				if (!data.replaceAll("TRAI", "PHAI").equals(data))
					data = data.replaceAll("TRAI", "PHAI");
				else
					data = data.replaceAll("PHAI", "TRAI");
				addUIPlayer(data);
				break;
			case "REMOVE":
				removeUIPlayer(data);
				break;
			case "START":
				mListGame.createGame(MainActivity.this);
				cancel(true);
				break;
			case "CANCEL":
				teamPhaiUI.removeAllViews();
				teamTraiUI.removeAllViews();
				findViewById(R.id.group_btn_first).setVisibility(View.VISIBLE);
				findViewById(R.id.group_btn_client).setVisibility(View.GONE);
				findViewById(R.id.text_room).setVisibility(View.VISIBLE);
				try {
					mSocket.close();
					cancel(true);
				} catch (IOException e) {
					e.printStackTrace();
				}
				break;
			case "CHECK":
				output.println("I'M_HERE");
			}

			super.onProgressUpdate(values);
		}

		public BufferedReader getInput() {
			return input;
		}

		public PrintWriter getOutput() {
			return output;
		}
		
		public Socket getSocket(){
			return mSocket;
		}
	}

	/**
	 * class Adapter serve 4 slide image of Game to choose game
	 * 
	 * @author baolong
	 * 
	 */
	private class ListGameAdapter extends FragmentStatePagerAdapter {
		public ListGameAdapter(FragmentManager fm) {
			super(fm);
		}

		@Override
		public Fragment getItem(int position) {
			return ListGame.createFrameImage(position);
		}

		@Override
		public int getCount() {
			return ListGame.NUMBER_OF_GAME;
		}
	}

	/**
	 * Class Listener serve 4 slide player in room That's used for kick player
	 * or help player change team
	 * 
	 * @author baolong
	 * 
	 */
	private class GestureListener extends SimpleOnGestureListener {

		private static final int SWIPE_MIN_DISTANCE = 50;
		private static final int SWIPE_THRESHOLD_VELOCITY = 20;
		View holderView;
		Player player;

		public GestureListener(View v, Player p) {
			super();
			holderView = v;
			player = p;
		}

		@Override
		public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
				float velocityY) {
			if (e1.getX() - e2.getX() > SWIPE_MIN_DISTANCE
					&& Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
				// From Right to Left
				switch (player.getTeam()) {
				case TRAI:
					mServer.mRoom.removePlayer(player);
					teamTraiUI.removeView(holderView);
					mServer.mRoom.send2AllPlayer("REMOVE_" + player.getName()
							+ ":TRAI");
					player.sendMessage("CANCEL_0");
					player.closeConnect();
					break;
				case PHAI:
					mServer.mRoom.changeTeam(player);
					teamPhaiUI.removeView(holderView);
					addUIPlayer(player);
					mServer.mRoom.send2AllPlayer("CHANGE_" + player.getName()
							+ ":PHAI");
					break;
				default:
				}
				Log.i("topcbl", "Phai qua trai - " + holderView.toString());
				return true;
			}

			else if (e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE
					&& Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
				// From Left to Right
				switch (player.getTeam()) {
				case TRAI:
					mServer.mRoom.changeTeam(player);
					teamTraiUI.removeView(holderView);
					addUIPlayer(player);
					mServer.mRoom.send2AllPlayer("CHANGE_" + player.getName()
							+ ":TRAI");
					break;
				case PHAI:
					mServer.mRoom.removePlayer(player);
					teamPhaiUI.removeView(holderView);
					mServer.mRoom.send2AllPlayer("REMOVE_" + player.getName()
							+ ":PHAI");
					player.sendMessage("CANCEL_0");
					player.closeConnect();
					break;
				default:
				}
				Log.i("topcbl", "trai qua phai - " + holderView.toString());
				return true;
			}

			if (e1.getY() - e2.getY() > SWIPE_MIN_DISTANCE
					&& Math.abs(velocityY) > SWIPE_THRESHOLD_VELOCITY) {
				// From Bottom to Top
				return true;
			} else if (e2.getY() - e1.getY() > SWIPE_MIN_DISTANCE
					&& Math.abs(velocityY) > SWIPE_THRESHOLD_VELOCITY) {
				// From Top to Bottom
				return true;
			}
			return false;
		}

		@Override
		public boolean onDown(MotionEvent e) {
			// always return true since all gestures always begin with onDown
			// and<br>
			// if this returns false, the framework won't try to pick up onFling
			// for example.
			return true;
		}
	}

	private class MyGestureDetector extends GestureDetector {
		String identification;
		GestureListener listener;

		public MyGestureDetector(Context context, GestureListener listener,
				String str) {
			super(context, listener);
			identification = str;
			this.listener = listener;
		}

		public String getIdentification() {
			return identification;
		}

		public GestureListener getListener() {
			return listener;
		}
	}

	/**
	 * Thêm mới và bắt sự kiện khi có người chơi mới kết nối tới server
	 * 
	 * @param newPlayer
	 *            :người chơi mới
	 */
	private void addUIPlayer(Player newPlayer) {
		if (newPlayer.getTeam() == Team.TRAI) {
			final ViewGroup newView = (ViewGroup) LayoutInflater.from(this)
					.inflate(R.layout.row_of_room, teamTraiUI, false);
			((TextView) newView.findViewById(R.id.text_view_row))
					.setText(newPlayer.getName());
			// don't let server player remove or move to another team
			if (!newPlayer.isServer()) {
				handleEvents4Room.add(new MyGestureDetector(this,
						new GestureListener(newView, newPlayer), newView
								.toString()));
				newView.setOnTouchListener(new View.OnTouchListener() {
					public boolean onTouch(View v, MotionEvent event) {
						for (int i = 0; i < handleEvents4Room.size(); i++) {
							if (handleEvents4Room.get(i).getIdentification()
									.equals(v.toString())) {
								return handleEvents4Room.get(i).onTouchEvent(
										event);
							}
						}
						return true;
					}
				});
			}
			teamTraiUI.addView(newView, teamTraiUI.getChildCount());
		} else {
			final ViewGroup newView = (ViewGroup) LayoutInflater.from(this)
					.inflate(R.layout.row_of_room, teamPhaiUI, false);
			((TextView) newView.findViewById(R.id.text_view_row))
					.setText(newPlayer.getName());
			handleEvents4Room
					.add(new MyGestureDetector(this, new GestureListener(
							newView, newPlayer), newView.toString()));
			newView.setOnTouchListener(new View.OnTouchListener() {
				public boolean onTouch(View v, MotionEvent event) {
					for (int i = 0; i < handleEvents4Room.size(); i++) {
						if (handleEvents4Room.get(i).getIdentification()
								.equals(v.toString())) {
							return handleEvents4Room.get(i).onTouchEvent(event);
						}
					}
					return true;
				}
			});
			teamPhaiUI.addView(newView, teamPhaiUI.getChildCount());
		}

	}

	/**
	 * Hàm thêm 1 player trong giao diện Room ở client
	 * 
	 * @param dataformat
	 *            namePlayer:Team. e.g: NguyenVanA:TRAI
	 * 
	 */
	private void addUIPlayer(String data) {
		String[] parseData = data.split(":");
		String name = parseData[0];
		String team = parseData[1];
		if (team.equals("TRAI")) {
			final ViewGroup newView = (ViewGroup) LayoutInflater.from(this)
					.inflate(R.layout.row_of_room, teamTraiUI, false);
			((TextView) newView.findViewById(R.id.text_view_row)).setText(name);
			teamTraiUI.addView(newView, teamTraiUI.getChildCount());
		} else {
			final ViewGroup newView = (ViewGroup) LayoutInflater.from(this)
					.inflate(R.layout.row_of_room, teamPhaiUI, false);
			((TextView) newView.findViewById(R.id.text_view_row)).setText(name);
			teamPhaiUI.addView(newView, teamPhaiUI.getChildCount());
		}

	}

	/**
	 * Hàm xóa 1 player trong giao diện Room ở client
	 * 
	 * @param data
	 *            format namePlayer:Team. e.g: NguyenVanB:PHAI
	 */
	private void removeUIPlayer(String data) {
		String[] parseData = data.split(":");
		String name = parseData[0];
		String team = parseData[1];
		if (team.equals("TRAI")) {
			for (int i = 0; i < teamTraiUI.getChildCount(); i++) {
				if (((TextView) teamTraiUI.getChildAt(i).findViewById(
						R.id.text_view_row)).getText().toString().equals(name)) {
					teamTraiUI.removeViewAt(i);
					break;
				}

			}
		} else {
			for (int i = 0; i < teamPhaiUI.getChildCount(); i++) {
				if (((TextView) teamPhaiUI.getChildAt(i).findViewById(
						R.id.text_view_row)).getText().toString().equals(name)) {
					teamPhaiUI.removeViewAt(i);
					break;
				}

			}
		}
	}

	class EnterIpDialog extends Dialog {
		Context mContext;
		EditText et1, et2, et3, et4;
		Button go, back;

		public EnterIpDialog(Context context) {
			super(context);
			mContext = context;
		}

		@Override
		protected void onCreate(Bundle savedInstanceState) {
			super.onCreate(savedInstanceState);
			setContentView(R.layout.dialog_enter_ip);
			et1 = (EditText) findViewById(R.id.dialog_ip_1);
			et2 = (EditText) findViewById(R.id.dialog_ip_2);
			et3 = (EditText) findViewById(R.id.dialog_ip_3);
			et4 = (EditText) findViewById(R.id.dialog_ip_4);
			go = (Button) findViewById(R.id.dialog_btn_go);
			back = (Button) findViewById(R.id.dialog_btn_back);
			back.setOnClickListener(new View.OnClickListener() {

				@Override
				public void onClick(View v) {
					dismiss();
				}
			});
			go.setOnClickListener(new View.OnClickListener() {

				@Override
				public void onClick(View v) {
					String IpAddress = et1.getText() + "." + et2.getText()
							+ "." + et3.getText() + "." + et4.getText();
					MainActivity.this.findViewById(R.id.group_btn_first).setVisibility(View.GONE);
					MainActivity.this.findViewById(R.id.group_btn_client).setVisibility(
							View.VISIBLE);
					MainActivity.mClient = new ClientThread(IpAddress);
					MainActivity.mClient.execute();
					dismiss();
					
					
				}

			});

		}
	}
}
